import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.lang.annotation.Repeatable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import sun.reflect.annotation.AnnotationSupport;
import sun.reflect.annotation.AnnotationType;

public interface MyAnnotatedElement {
    /**
     * 判断指定类型的注解是否存在于该元素上。
     * 主要用于方便访问标记注解。
     *
     * @param annotationClass 注解类型的 Class 对象
     * @return 如果指定类型的注解存在，返回 true，否则返回 false
     * @throws NullPointerException 如果给定的注解类为 null
     * @since 1.5
     */
    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return getAnnotation(annotationClass) != null;
    }

    /**
     * 返回指定类型的注解，如果该注解存在，则返回；否则返回 null。
     *
     * @param <T> 要查询并返回的注解的类型
     * @param annotationClass 注解类型的 Class 对象
     * @return 如果该元素上存在指定类型的注解，则返回该注解；否则返回 null
     * @throws NullPointerException 如果给定的注解类为 null
     * @since 1.5
     */
    <T extends Annotation> T getAnnotation(Class<T> annotationClass);

    /**
     * 返回此元素上存在的注解。
     * 如果没有注解存在，则返回长度为 0 的数组。
     *
     * @return 此元素上存在的所有注解
     * @since 1.5
     */
    Annotation[] getAnnotations();

    /**
     * 返回与该元素关联的注解。
     * 如果没有注解关联，则返回长度为 0 的数组。
     *
     * @param <T> 要查询并返回的注解的类型
     * @param annotationClass 注解类型的 Class 对象
     * @return 所有与此元素关联的注解，如果没有则返回长度为 0 的数组
     * @throws NullPointerException 如果给定的注解类为 null
     * @since 1.8
     */
    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
        // 先获取直接存在的注解
        T[] result = getDeclaredAnnotationsByType(annotationClass);

        // 如果没有直接存在的注解且当前元素是类且注解是可继承的，则查找超类
        if (result.length == 0 && this instanceof Class &&
                AnnotationType.getInstance(annotationClass).isInherited()) {
            Class<?> superClass = ((Class<?>) this).getSuperclass();
            if (superClass != null) {
                result = superClass.getAnnotationsByType(annotationClass);
            }
        }

        return result;
    }

    /**
     * 返回此元素的注解，如果该注解直接存在，则返回；否则返回 null。
     * 忽略继承的注解。
     *
     * @param <T> 要查询并返回的注解的类型
     * @param annotationClass 注解类型的 Class 对象
     * @return 如果该元素上直接存在指定类型的注解，则返回该注解；否则返回 null
     * @throws NullPointerException 如果给定的注解类为 null
     * @since 1.8
     */
    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        for (Annotation annotation : getDeclaredAnnotations()) {
            if (annotationClass.equals(annotation.annotationType())) {
                return annotationClass.cast(annotation);
            }
        }
        return null;
    }

    /**
     * 返回此元素的注解，如果该注解是直接或间接存在，则返回；否则返回长度为 0 的数组。
     * 忽略继承的注解。
     *
     * @param <T> 要查询并返回的注解的类型
     * @param annotationClass 注解类型的 Class 对象
     * @return 所有直接或间接存在的指定类型的注解，如果没有则返回长度为 0 的数组
     * @throws NullPointerException 如果给定的注解类为 null
     * @since 1.8
     */
    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return AnnotationSupport.getDirectlyAndIndirectlyPresent(
                Arrays.stream(getDeclaredAnnotations()).collect(Collectors.toMap(Annotation::annotationType,
                        Function.identity(), (first, second) -> first, LinkedHashMap::new)),
                annotationClass);
    }

    /**
     * 返回此元素上直接存在的注解。
     * 忽略继承的注解。
     * 如果没有直接存在的注解，则返回长度为 0 的数组。
     *
     * @return 此元素上直接存在的所有注解
     * @since 1.5
     */
    Annotation[] getDeclaredAnnotations();

}
